package com.lantosec.hmrp.core.kit;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
 * request中的getRead() 和 getInputStream()在读取一次后标记为-1，无法再次被读取。
 * 所以如果数据在filter中被读取，将无法在@RequestBody中再次读取。
 * 此时解决方案，将request进行包装（装饰者模式），并重写getInputStream()和getRead()方法。
 *
 * @author 杨成宇
 * @version 1.0
 */
public class RequestWrapper  extends HttpServletRequestWrapper {
    private final String body;
    private final int BUFFER_SIZE = 1024 * 8;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.body = read(request);
    }
    public String getBody() {
        return body;
    }
    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes());
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() {
                return bais.read();
            }
        };
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }


    private String read(HttpServletRequest request) throws IOException {
        BufferedReader bufferedReader = request.getReader();
        StringWriter writer = new StringWriter();
        write(bufferedReader, writer);
        return writer.getBuffer().toString();
    }

    private long write(Reader reader, Writer writer) throws IOException {
        return write(reader, writer, BUFFER_SIZE);
    }

    private long write(Reader reader, Writer writer, int bufferSize) throws IOException {
        int read;
        long total = 0;
        char[] buf = new char[bufferSize];
        while ((read = reader.read(buf)) != -1) {
            writer.write(buf, 0, read);
            total += read;
        }
        return total;
    }
}
